// *********************************************************************************
// Project Name : zkx2024
// Author       : Jlan
// Email        : 15533610762@163.com
// Create Time  : 2024-04-26
// File Name    : tx.v
// Module Name  :
// Called By    :
// Abstract     :tx transcate data which is from st_tx_bus fristly.If the
// rd_bus is transcating data but st_tx occur,tx still transcate st_tx_bus
// data fristly.
//
// 
// *********************************************************************************
// Modification History:
// Date         By              Version                 Change Description
// -----------------------------------------------------------------------
// 2024-04-26    Macro           1.0                     Original
//  
// *********************************************************************************
module tx(
    input               CLK,
    input               RST_N,
    rd_bus.slave        rd_bus,
    st_tx_dd_bus.slave  st_bus,
    rd_bus_error.master rd_e_bus
    );
//parameter
parameter       DATA_WIDTH  =  32;
parameter       CRC_WIDTH   =  4;
//-----------I/O define-----------------------//
logic   [0:0]   CLK;
logic   [0:0]   RST_N;
//-----------I/O define-----------------------//
//-----------Inter signal define--------------//
//-----tx_fsm_signal
typedef enum {IDLE,
              DD_SOP,
              DD_EOP,
              RD_SOP,
              RD_EOP
    } tx_st_t;

tx_st_t tx_st_c,tx_st_n;
//----tx_crc_check_signal
logic   [31:0]          crc_in;
logic   [0:0]           vld_d;
logic   [0:0]           vld_2d;
logic   [0:0]           eop_d;
logic   [0:0]           eop_2d;
logic   [35:0]          tran_data_d;
logic   [35:0]          tran_data_2d;
logic   [CRC_WIDTH-1:0] crc_check;
logic   [0:0]           crc_check_vld;
logic   [0:0]           check_pass;
//-----------Inter signal define--------------//
//------------tx_fsm--------------------------//
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)begin
        tx_st_c <=  IDLE;
    end
    else begin
        tx_st_c <=  tx_st_n;
    end
end 

always_comb begin
    tx_st_n = tx_st_c;
    case(tx_st_c)
        IDLE:begin
            if(st_bus.WR_SOP)
                tx_st_n = DD_SOP;
            else if(!st_bus.WR_SOP&&
                    rd_bus.RD_SOP)
                tx_st_n = RD_SOP;
            else
                tx_st_n = IDLE;
        end
        DD_SOP:begin
            if(st_bus.WR_EOP)
                tx_st_n = DD_EOP;
            else
                tx_st_n = DD_SOP;
        end
        DD_EOP:begin
            if(rd_e_bus.RD_EOP)
                tx_st_n = IDLE;
            else
                tx_st_n = DD_EOP;
        end
        RD_SOP:begin
            if(st_bus.WR_SOP)
                tx_st_n = DD_SOP;
            else if(rd_bus.RD_EOP)
                tx_st_n = RD_EOP;
            else
                tx_st_n = RD_SOP;
        end
        RD_EOP:begin
            if(rd_e_bus.RD_EOP)
                tx_st_n = IDLE;
            else
                tx_st_n = RD_EOP;
        end
        default:begin
            tx_st_n =   IDLE;
        end
    endcase
end
//------------tx_fsm--------------------------//

//To do crc_check need to 2_stages pipeline for tran_data
//but direct deliver does not need.
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)begin
        tran_data_d <= '0;
        tran_data_2d<= '0;
        vld_d       <= '0;
        vld_2d      <= '0;
    end
    else if(rd_bus.RD_VLD)begin
        tran_data_d <= rd_bus.RD_DATA;
        vld_d       <=  1'b1;
        tran_data_2d<= tran_data_d;
        vld_2d      <=  vld_d;
    end
    else begin
        vld_2d      <= vld_d;
        tran_data_2d<= tran_data_d;
    end
end
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)begin
        eop_2d  <= '0;
        eop_d   <= '0;
    end
    else begin
        eop_d   <= rd_bus.RD_EOP;
        eop_2d  <= eop_d;
    end
end 
//------------------2_stages_pipeline--------------//
//instance crc_en
assign  crc_in  =   {32{rd_bus.RD_VLD}} & rd_bus.RD_DATA[31:0];
en_crc  u0(
    .CLK(CLK),
    .RST_N(RST_N),
    .I_DATA(crc_in),
    .CRC_OUT(crc_check),
    .OUT_VLD(crc_check_vld)
    );
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)
        check_pass  <= '0;
    else if(crc_check_vld &&
            (crc_check==tran_data_d[35:32])
        )
        check_pass  <= 1'b1;
    else
        check_pass  <= 1'b0;
end 
//-----------------crc_end-------------------//
//All sop can trigger tx send sop
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)begin
        rd_e_bus.RD_SOP  <= '0;
    end
    else if(rd_bus.RD_SOP||
            st_bus.WR_SOP)
        rd_e_bus.RD_SOP  <= 1'b1;
    else
        rd_e_bus.RD_SOP  <= '0;
end 
//--------------------------------------------
//priority transmisssion direct deliver
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)begin
        rd_e_bus.RD_VLD  <= '0;
        rd_e_bus.RD_DATA <= '0;
        rd_e_bus.RD_ERROR<= '0;
    end
    else if(tx_st_c==DD_SOP)begin
        rd_e_bus.RD_VLD  <= st_bus.WR_VLD;
        rd_e_bus.RD_DATA <= st_bus.WR_DATA;
        rd_e_bus.RD_ERROR<= '0;
    end
    else if(tx_st_c==RD_SOP)begin
        rd_e_bus.RD_VLD  <= vld_2d;
        rd_e_bus.RD_DATA <= tran_data_2d[31:0];
        rd_e_bus.RD_ERROR<= !check_pass;
    end
    else
        rd_e_bus.RD_VLD  <= '0;
end 

always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)
        rd_e_bus.RD_EOP  <= '0;
    else if(tx_st_c==DD_SOP&&
            st_bus.WR_EOP)
        rd_e_bus.RD_EOP  <= 1'b1;
    else if(tx_st_c==RD_SOP&&
            eop_2d)
        rd_e_bus.RD_EOP  <= 1'b1;
    else
        rd_e_bus.RD_EOP  <=  '0;
end 

//--------------------------------------------//

endmodule
